package com.guli.ucenter.controller.api;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.guli.common.constants.ResultCodeEnum;
import com.guli.common.exception.RRException;
import com.guli.common.vo.R;
import com.guli.ucenter.entity.Member;
import com.guli.ucenter.service.MemberService;
import com.guli.ucenter.util.ConstantPropertiesUtil;
import com.guli.ucenter.util.CookieUtils;
import com.guli.ucenter.util.JwtUtils;
import com.guli.ucenter.vo.LoginInfoVo;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;

@Controller
@RequestMapping("/api/ucenter/wx")
public class WxApiController {
	@Autowired
	private MemberService memberService;
	@Autowired
	private StringRedisTemplate redisTemplate;

	private static final String WX_OPEN_STATE = "wx_open_state";
	private static final String GULI_JWT_TOKEN = "guli_jwt_token";

	/**
	 * 跳转到微信二维码登录页面
	 */
	@GetMapping("/login")
	public String genQrConnect(Model model) {
		// 微信开放平台授权baseUrl
		String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
				"?appid=%s" +
				"&redirect_uri=%s" +
				"&response_type=code" +
				"&scope=snsapi_login" +
				"&state=%s" +
				"#wechat_redirect";

		// 回调地址
		String redirectUrl = ConstantPropertiesUtil.WX_OPEN_REDIRECT_URL; //获取业务服务器重定向地址
		try {
			redirectUrl = URLEncoder.encode(redirectUrl, "UTF-8"); //url编码
		} catch (UnsupportedEncodingException e) {
			throw new RRException(ResultCodeEnum.URL_ENCODE_ERROR);
		}

		// 生成 state 参数，防止csrf攻击（跨站请求伪造攻击）
		String state = IdUtil.randomUUID();
		redisTemplate.opsForValue().set(WX_OPEN_STATE, state, 5, TimeUnit.MINUTES);

		//生成qrcodeUrl
		String qrcodeUrl = String.format(
				baseUrl,
				ConstantPropertiesUtil.WX_OPEN_APP_ID,
				redirectUrl,
				state);

//		return "redirect:" + qrcodeUrl;
		String QrCodeUrl = memberService.getQRCodeUrl(state);
		model.addAttribute("url",QrCodeUrl);
		model.addAttribute("state",state);
		return "redirect:" + QrCodeUrl;
	}


	@GetMapping("/callback")
	public String callback(String code, String state, HttpServletResponse response, HttpServletRequest request) {
		// 验证 state,防止跨站请求伪造攻击
		String stateStr = redisTemplate.opsForValue().get(WX_OPEN_STATE);
		if (StrUtil.isEmpty(code) || StrUtil.isEmpty(stateStr) || !state.equals(stateStr)) {
			throw new RRException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
		}

		Member member = memberService.callback(code,state);
		// 登录 生成jwt
		String guliJwtToken = JwtUtils.geneJsonWebToken(member);
		// 存入cookie，超时时间30分钟
		CookieUtils.setCookie(request, response, GULI_JWT_TOKEN, guliJwtToken, 60 * 30);
		return "redirect:http://localhost:3000?token=" + guliJwtToken;
	}

	/**
	 * 获取jwt token
	 */
	@GetMapping("/get-jwt")
	@ResponseBody
	public R getJwt(HttpServletRequest request) {
		String guliJwtToken = CookieUtils.getCookieValue(request, GULI_JWT_TOKEN);
		return R.ok().data(GULI_JWT_TOKEN, guliJwtToken);
	}

	/**
	 * 解析jwt token
	 */
	@PostMapping("/parse-jwt")
	@ResponseBody
	public R getLoginInfoByJwtToken(@RequestBody String jwtToken){

		Claims claims = JwtUtils.checkJWT(jwtToken);

		String id = (String)claims.get("id");
		String nickname = (String)claims.get("nickname");
		String avatar = (String)claims.get("avatar");

		LoginInfoVo loginInfoVo = new LoginInfoVo();
		loginInfoVo.setId(id);
		loginInfoVo.setNickname(nickname);
		loginInfoVo.setAvatar(avatar);

		return R.ok().data("loginInfo", loginInfoVo);

	}

	/**
	 * 通过state查询用户是否已经登录
	 */
	@GetMapping("/checkLogin")
	@ResponseBody
	public R checkLoginByState(String state){
		Member member = memberService.getOne(new LambdaQueryWrapper<Member>().eq(Member::getState, state));
		return member == null ? R.error() : R.ok();
	}
}